package com.mobimap.nhom9.gui.utls;

import android.graphics.Point;

import com.mobimap.nhom9.dto.LocationDTO;


    public class LocateUtils
    {
       static  final double MinLatitude = -85.05112878;
        static final double MaxLatitude = 85.05112878;
        static final double MinLongitude = -177;
        static final double MaxLongitude = 177;
        static Size tileDefaultSize = new Size(256, 256);

        private static double Clip(double n, double minValue, double maxValue)
        {
            return Math.min(Math.max(n, minValue), maxValue);
        }

        private static Size GetTileMatrixSizePixel(int zoom)
        {
            Size s = GetTileMatrixSizeXY(zoom);
            return new Size(s.Width * tileDefaultSize.Width, s.Height * tileDefaultSize.Height);
        }

        private static Size GetTileMatrixMaxXY(int zoom)
        {
            int xy = (1 << zoom);
            return new Size(xy - 1, xy - 1);
        }

        private static Size GetTileMatrixMinXY(int zoom)
        {
            return new Size(0, 0);
        }

        private static Size GetTileMatrixSizeXY(int zoom)
        {
            Size sMin = GetTileMatrixMinXY(zoom);
            Size sMax = GetTileMatrixMaxXY(zoom);

            return new Size(sMax.Width - sMin.Width + 1, sMax.Height - sMin.Height + 1);
        }

        public static Point ToPoint(LocationDTO geoCoordinate, int zoom)
        {
            Point ret = new Point();
            double  latitude = Clip(geoCoordinate.getLatitude(), MinLatitude, MaxLatitude);
            double longitude = Clip(geoCoordinate.getLongitude(), MinLongitude, MaxLongitude);

            double x = (longitude+ 180) / 360;
            double sinLatitude = Math.sin(latitude * Math.PI / 180);
            double y = 0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);

            Size s = GetTileMatrixSizePixel(zoom);
            int mapSizeX = s.Width;
            int mapSizeY = s.Height;

            ret.x = (int)Clip(x * mapSizeX + 0.5, 0, mapSizeX - 1);
            ret.y = (int)Clip(y * mapSizeY + 0.5, 0, mapSizeY - 1);

            return ret;
        }

        public static Point ToPoint(double longitude, double latitude, int zoom)
        {
            Point ret = new Point();
            latitude = Clip(latitude, MinLatitude, MaxLatitude);
            longitude = Clip(longitude, MinLongitude, MaxLongitude);

            double x = (longitude + 180) / 360;
            double sinLatitude = Math.sin(latitude * Math.PI / 180);
            double y = 0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);

            Size s = GetTileMatrixSizePixel(zoom);
            int mapSizeX = s.Width;
            int mapSizeY = s.Height;

            ret.x = (int)Clip(x * mapSizeX + 0.5, 0, mapSizeX - 1);
            ret.y = (int)Clip(y * mapSizeY + 0.5, 0, mapSizeY - 1);

            return ret;

        }

        public static LocationDTO ToGeographicCoordinate(Point point, int zoom)
        {
        	LocationDTO ret = new LocationDTO();
            Size s = GetTileMatrixSizePixel(zoom);
            double mapSizeX = s.Width;
            double mapSizeY = s.Height;
            double xx = (Clip(point.x, 0, mapSizeX - 1) / mapSizeX) - 0.5;
            double yy = 0.5 - (Clip(point.y, 0, mapSizeY - 1) / mapSizeY);
            ret.setLatitude( 90 - 360 * Math.atan(Math.exp(-yy * 2 * Math.PI)) / Math.PI);
            ret.setLongitude( 360 * xx);
            return ret;
        }

        public static LocationDTO ToGeographicCoordinate(int X, int Y, int zoom)
        {
        	LocationDTO ret = new LocationDTO();

            Size s = GetTileMatrixSizePixel(zoom);
            double mapSizeX = s.Width;
            double mapSizeY = s.Height;

            double xx = (Clip(X, 0, mapSizeX - 1) / mapSizeX) - 0.5;
            double yy = 0.5 - (Clip(Y, 0, mapSizeY - 1) / mapSizeY);

            ret.setLatitude( 90 - 360 * Math.atan(Math.exp(-yy * 2 * Math.PI)) / Math.PI);
            ret.setLongitude(360 * xx);
            return ret;
        }

        public static Point ToTile(double longitude, double latitude, int zoom)
        {
            Point result = ToPoint(longitude, latitude, zoom);
            result.x /= 256;
            result.y /= 256;
            return result;
        }

        public static Point ToTile(LocationDTO coordiante, int zoom)
        {
            Point result = ToPoint(coordiante, zoom);
            result.x /= 256;
            result.y /= 256;
            return result;
        }

        public static Point ToTile(Point globalPoint, int zoom)
        {
            LocationDTO coordinate = ToGeographicCoordinate(globalPoint, zoom);
            return ToTile(coordinate, zoom);
        }
    }
